<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/10/17
 * Time: 19:39
 */
namespace app{
    use C\ctr;
    use C\lib\Db;
    use C\mod\worker;
    use C\mod\proute;
    use C\mod\order;
    require LIB_PATH. 'WxpayAPI/lib/WxPay.Config.php';
    class wx extends ctr{
        private $appid=\WxPayConfig::APPID;
        private $mch_id=\WxPayConfig::MCHID;
        private $key=\WxPayConfig::KEY;
        private $appsercret=\WxPayConfig::APPSECRET;
        private $notify_url=\WxPayConfig::NOTIFY_URL;
        private $trade_type='APP';
        private $sslcert_path=\WxPayConfig::SSLCERT_PATH;
        private $sslkey_path=\WxPayConfig::SSLKEY_PATH;

        //private $data_path = LIB_PATH."WxpayAPI/logs/wxpay.txt";//日志文件
        public function wxPay(){
            //echo $appid=\WxPayConfig::APPID;exit;
            //var_dump($_SERVER['REMOTE_ADDR']);
            if($post = 1){
                //上传传用户id，充值金额
                //$uid=$bpost['uid'];
                //$money=$bpost['money'];
                //$type=$bpost['type']
                $money=50;



                $user=1;
                if($user){

                    $res=$this->pay($user,$money);
                }else{
                    // $this->writeAesJson(1,'请先注册再来充值押金吧!',0);
                    echo 0;
                }

                echo json_encode($res);
            }
        }

        private function userFind($uid){
            Db::connect();
            $worker = New \C\mod\worker();
            //$proute = New \C\mod\proute();
            $user=worker::get(['id'=>$uid]);
            return $user;
        }

        /*调用统一支付接口*/
        public function pay($user,$money)
        {

            $rechargeNum=order::build_order_no();//订单号
            $user=2;
            if ($user) {
                //微信支付商品信息
                $data = array(
                    'body' => '便递押金',  //商品描述
                    'out_trade_no' => $rechargeNum,      //商户订单号
                    'spbill_create_ip' => self::get_client_ip(),  //用户端实际ip
                    'total_fee' => $money * 100,//支付金额
                    'time_start' => time(),
                );
                //var_dump($data);
                $urlcon = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
                $postdata = self::setSendData($data);
                var_dump($postdata);
                $host = $urlcon;

                $ch = curl_init();

                curl_setopt($ch, CURLOPT_POST, 1);
                curl_setopt($ch, CURLOPT_HEADER, 0);
                curl_setopt($ch, CURLOPT_URL, $host);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
                curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
                curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);

                $output = curl_exec($ch);
                if($output === FALSE ){

                    echo "CURL Error:".curl_error($ch);
                }
                curl_close($ch);
                var_dump($output);//false
                $predata = $this->xmlToObject($output);
                var_dump($predata);
                // 如果解析的结果为false，终止程序
                echo 111;
                if ($predata === false) {echo 22;
                    $code = 1006;
                    $msg = '请求失败';
                    $this->echoMsg($code, $msg, $data);
                    exit;

                }
                // 如果微信返回错误码为FAIL，则代表请求失败，返回失败信息；缺少参数
                if ($predata->return_code == 'FAIL') {echo 33;
                    $code = 1006;
                    $msg = '请求失败';
                    $data['msg'] = $predata->return_msg;
                    $this->echoMsg($code, $msg, $data);
                    exit;

                } else {
                    //请求成功，将支付信息存入数据库  写添加代码
                    echo 55;
                    $res=1;
                    if (($res) <= 0) {
                        $this->echoMsg(0, '请重新请求', $data);
                        exit;
                    }

                    //如果上一次请求成功，那么我们将返回的数据重新拼装，进行第二次签名
                    $resignData = array(
                        'appid' => $predata->appid,
                        'partnerid' => $predata->mch_id,
                        'prepayid' => $predata->prepay_id,
                        'noncestr' => $predata->nonce_str,
                        'timestamp' => time(),
                        'package' => 'Sign=WXPay'
                    );
                    //二次签名；
                    $sign = $this->getSign($resignData);
                    $datainfo['appid'] = $predata->appid;
                    $datainfo['mch_id'] = $predata->mch_id;
                    $datainfo['nonce_str'] = $predata->nonce_str;
                    $datainfo['prepay_id'] = $predata->prepay_id;
                    $datainfo['sign'] = $sign;
                    $datainfo['time'] = $resignData['timestamp'];
                    $datainfo['packages'] = $resignData['package'];
                    $datainfo['order'] = $data['out_trade_no'];
                    /*$fp = fopen($this->data_path, 'a+bdUser');
                    fwrite($fp, print_r($datainfo, true));
                    fclose($fp);*/
                    $this->echoMsg(1, $rechargeNum, $datainfo);
                    exit;
                }
            }
        }



        /**
         * 生成随机数并返回
         */
        private function getNonceStr()
        {
            $code = "";
            for ($i = 0; $i > 10; $i++) {
                $code .= mt_rand(1000);        //获取随机数
            }
            $nonceStrTemp = md5($code);
            $nonce_str = strtolower(mb_substr($nonceStrTemp, 5, 37));      //MD5加密后截取32位字符
            return $nonce_str;
        }

        /**
         * 拼装请求的数据
         * @return  String 拼装完成的数据
         */
        private function setSendData($data)
        {
            $nonce_str = $this->getNonceStr();      //调用随机字符串生成方法获取随机字符串
            $data['nonce_str']=$nonce_str;
            $data['appid'] = $this->appid;
            $data['attach'] = "便递支付测试";
            $data['mch_id'] = $this->mch_id;
            $data['nonce_str'] = $nonce_str;
            $data['notify_url'] = $this->notify_url;
            $data['trade_type'] = $this->trade_type;     //将参与签名的数据保存到数组
            $data['sign_type'] = 'MD5';
            $data['detail'] = '支付测试';
            $data['limit_pay'] = 'no_credit';

            // 注意：以上几个参数是追加到$data中的，$data中应该同时包含开发文档中要求必填的剔除sign以外的所有数据
            $sign = $this->getSign($data);        //获取签名
            //$data = sprintf($sTpl, self::$appid, $data['body'], self::$mch_id, $nonce_str, self::$notify_url, $data['out_trade_no'], $data['spbill_create_ip'], $data['total_fee'], self::$trade_type, $sign);
            $data['sign']=$sign;
            //生成xml数据格式
            $xmls=$this->data_to_xml($data);
            return $xmls;
        }

        //异步回调
        public function wxNotify(){
            $obj=$this->notice();
            //接收返回订单的信息
            if ($obj) {
                $data = array(
                    'appid' => $obj->appid,
                    'mch_id' => $obj->mch_id,
                    'nonce_str' => $obj->nonce_str,
                    'result_code' => $obj->result_code,
                    'openid' => $obj->openid,
                    'trade_type' => $obj->trade_type,
                    'bank_type' => $obj->bank_type,
                    'total_fee' => $obj->total_fee,
                    'cash_fee' => $obj->cash_fee,
                    'transaction_id' => $obj->transaction_id,
                    'out_trade_no' => $obj->out_trade_no,
                    'time_end' => $obj->time_end
                );
                $fp = fopen(LIB_PATH.'WxpayAPI/logs/pay.txt', 'a+bdUser');
                fwrite($fp, print_r($data, true));
                fclose($fp);
                // 拼装数据进行第三次签名
                $sign = $this->getSign($data);        // 获取签名
                /** 将签名得到的sign值和微信传过来的sign值进行比对，如果一致，则证明数据是微信返回的。 */
                if ($sign == $obj->sign) {
                    $reply = "<xml>
                                    <return_code><![CDATA[SUCCESS]]></return_code>
                                    <return_msg><![CDATA[OK]]></return_msg>
                                  </xml>";
                    echo $reply;      // 向微信后台返回结果。
                }
                //查询改订单是否存在
                $datad = array(
                    'appid' => $obj->appid,
                    'mch_id' => $obj->mch_id,
                    'out_trade_no' => $obj->out_trade_no,
                    'nonce_str' => $obj->nonce_str
                );
                $sign = $this->getSign($datad);
                $xml_data = '<xml>
                                       <appid>%s</appid>
                                       <mch_id>%s</mch_id>
                                       <nonce_str>%s</nonce_str>
                                       <out_trade_no>%s</out_trade_no>
                                       <sign>%s</sign>
                                       </xml>';
                $xml_data2 = sprintf($xml_data, $this->appid, $this->mch_id, $datad['nonce_str'], $datad['out_trade_no'], $sign);
                $url = "https://api.mch.weixin.qq.com/pay/orderquery";
                $host = $url;
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_POST, 1);
                curl_setopt($ch, CURLOPT_HEADER, 0);
                curl_setopt($ch, CURLOPT_URL, $host);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_data2);
                $output = curl_exec($ch);
                $querydata = $this->xmlToObject($output);
                $dd = array(
                    'state' => $querydata->trade_state
                );
//                $fp = fopen($this->data_path, 'a+bdUser');
//                fwrite($fp, print_r($dd, true));
//                fclose($fp);
                //获取支付成功信息，更改数据库支付状态
                if ($querydata->trade_state == "SUCCESS") {

                    //$this->updata($obj->out_trade_no,$obj->total_fee);
                }
            }
        }
        public function notice(){
            $postXml = $GLOBALS["HTTP_RAW_POST_DATA"];// 接受通知参数；
            if (empty($postXml)) {
                return false;
            }
            $postObj = $this->xmlToObject($postXml);// 调用解析方法，将xml数据解析成对象
            if ($postObj === false) {
                return false;
            }
            if (!empty($postObj->return_code)) {
                if ($postObj->return_code == 'FAIL') {
                    return false;
                }
            }
            return $postObj;          // 返回结果对象；
        }

        /**
         * 输出xml字符
         * @param	$params		参数名称
         * return	string		返回组装的xml
         **/
        public function data_to_xml( $params ){
            if(!is_array($params)|| count($params) <= 0)
            {
                return false;
            }
            $xml = "<xml>";
            foreach ($params as $key=>$val)
            {
                if (is_numeric($val)){
                    $xml.="<".$key.">".$val."</".$key.">";
                }else{
                    $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
                }
            }
            $xml.="</xml>";
            return $xml;
        }
        /**
         * 获取参数签名；
         * @param  Array  要传递的参数数组
         * @return String 通过计算得到的签名；
         */
        public function getSign($params)
        {
            ksort($params);        //将参数数组按照参数名ASCII码从小到大排序
            foreach ($params as $key => $item) {
                if (!empty($item)) {         //剔除参数值为空的参数
                    $newArr[] = $key . '=' . $item;     // 整合新的参数数组
                }
            }
            $stringA = implode("&", $newArr);         //使用 & 符号连接参数
            $stringSignTemp = $stringA . "&key=" . $this->key;        //拼接key
            // key是在商户平台API安全里自己设置的
            $stringSignTemp = MD5($stringSignTemp);       //将字符串进行MD5加密
            $sign = strtoupper($stringSignTemp);      //将所有字符转换为大写
            return $sign;
        }

        /**
         * 解析xml文档，转化为对象
         * @author 栗荣发 2016-09-20
         * @param  String $xmlStr xml文档
         * @return Object         返回Obj对象
         */
        public function xmlToObject($xmlStr)
        {
            if (!is_string($xmlStr) || empty($xmlStr)) {
                echo "pppppp";
                return false;
            }

            // 由于解析xml的时候，即使被解析的变量为空，依然不会报错，会返回一个空的对象，所以，我们这里做了处理，当被解析的变量不是字符串，或者该变量为空，直接返回false
            $postObj = simplexml_load_string($xmlStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            $postObj = json_decode(json_encode($postObj));
            //将xml数据转换成对象返回
            return $postObj;
        }


        /**
         * 返回接口数据
         */
        public function echoMsg($code, $msg, $data)
        {
            $redata = array();
            //$data不为空
            if (!empty($data)) {
                if (is_array($data)) {//传入数组
                    $redata = $data;
                } else {//传入字符串
                    $redata = $data;
                }
            }
            if ($code == 0) {//识别码为0
                $reMsg = array('code' => $code, 'msg' => $msg);
                return $reMsg;
                //$this->writeAesJson(1, ['bcards' => $jBcards],0);
                //echo json_encode($reMsg);
            } else {//识别码不为0
                $reMsg = array(
                    'code' => $code,
                    'msg' => $msg,
                    'data' => $redata
                );
                return $reMsg;
                //$this->writeAesJson(1, ['bcards' => $jBcards],0);
                //echo json_encode($reMsg);
            }
        }
        /*
         * 获取用户真实ip
         */
        private function get_client_ip($type = 0,$adv=false) {
            $type       =  $type ? 1 : 0;
            static $ip  =   NULL;
            if ($ip !== NULL) return $ip[$type];
            if($adv){
                if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                    $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
                    $pos    =   array_search('unknown',$arr);
                    if(false !== $pos) unset($arr[$pos]);
                    $ip     =   trim($arr[0]);
                }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
                    $ip     =   $_SERVER['HTTP_CLIENT_IP'];
                }elseif (isset($_SERVER['REMOTE_ADDR'])) {
                    $ip     =   $_SERVER['REMOTE_ADDR'];
                }
            }elseif (isset($_SERVER['REMOTE_ADDR'])) {
                $ip     =   $_SERVER['REMOTE_ADDR'];
            }
            // IP地址合法验证
            $long = sprintf("%u",ip2long($ip));
            $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
            return $ip[$type];
        }

    }
}